home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
IRIX 6.2 Applications 1996 May
/
SGI IRIX 6.2 Applications 1996 May.iso
/
dist
/
impr_dev.idb
/
usr
/
impressario
/
src
/
libimp
/
impRowIO.c.z
/
impRowIO.c
Wrap
C/C++ Source or Header
|
1996-05-06
|
21KB
|
747 lines
/**************************************************************************
*
* Copyright (c) 1993 Silicon Graphics, Inc.
* All Rights Reserved
*
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SGI
*
* The copyright notice above does not evidence any actual of intended
* publication of such source code, and is an unpublished work by Silicon
* Graphics, Inc. This material contains CONFIDENTIAL INFORMATION that is
* the property of Silicon Graphics, Inc. Any use, duplication or
* disclosure not specifically authorized by Silicon Graphics is strictly
* prohibited.
*
* RESTRICTED RIGHTS LEGEND:
*
* Use, duplication or disclosure by the Government is subject to
* restrictions as set forth in subdivision (c)(1)(ii) of the Rights in
* Technical Data and Computer Software clause at DFARS 52.227-7013,
* and/or in similar or successor clauses in the FAR, DOD or NASA FAR
* Supplement. Unpublished - rights reserved under the Copyright Laws of
* the United States. Contractor is SILICON GRAPHICS, INC., 2011 N.
* Shoreline Blvd., Mountain View, CA 94039-7311
**************************************************************************
*
* File: impRowIO.c
*
* Description: Image row read and write routines.
*
**************************************************************************/
#ident "$Revision: 1.6 $"
#include <stdio.h>
#include <sys/types.h>
#include <assert.h>
#include "impI.h"
/* Local functions */
static int rleGetRowSize(IMPImage *image, ushort_t row, ushort_t channel);
static int rleSetRowSize(IMPImage *image, long count, ushort_t row,
ushort_t channel);
static void rleExpandRow(short *rleBuf, int ibpp, short *expBuf, int obpp);
static int rleCompactRow(short *expBuf, int ibpp, short *rleBuf, int obpp,
int npixels);
/**************************************************************************
*
* Function: impWriteRow
*
* Description: Writes the specified image data as the specified row and
* channel.
*
* Parameters:
* image (I) - image to write
* buffer (I) - data to write
* row (I) - image row to write
* channel (I) - image channel to write
*
* Return: Number of pixels written if no error. -1 and IMPerrno set if
* errors.
*
**************************************************************************/
int impWriteRow(IMPImage *image, short *buffer, ushort_t row, ushort_t channel) {
register long vmin, vmax;
register ushort_t x;
register short *sptr;
int count, retv;
/*
* Sanity check the inputs
*/
assert(image != NULL);
assert(buffer != NULL);
/*
* Verify we can write image
*/
if (!_impWriting(image))
_impReturnError(IMP_ERR_WRITEFLAG);
/*
* Use image dimension to sanitize the row and channel values
*/
if (impDimension(image) < 3)
channel = 0;
if (impDimension(image) < 2)
row = 0;
/*
* Determine the min and max image data values. Note that
* for 1 BPP we are packing the data as uchar into tmpbuf.
* We can just write this for the 1 BPP VERBATIM case.
*/
vmin = impMinValue(image);
vmax = impMaxValue(image);
sptr = buffer;
switch (impRasterBPP(image)) {
case 1:
{
register uchar_t *cptr = (uchar_t*)image->tmpbuf;
for (x = impXSize(image); x--; ) {
*cptr = (uchar_t)(*sptr++);
/* LINTED */
if (*cptr > vmax) vmax = *cptr;
/* LINTED */
if (*cptr < vmin) vmin = *cptr;
cptr++;
}
}
break;
case 2:
for (x = impXSize(image); x--; ) {
/* LINTED */
if ((unsigned short)*sptr > vmax)
vmax = (unsigned short)*sptr;
/* LINTED */
if ((unsigned short)*sptr < vmin)
vmin = (unsigned short)*sptr;
sptr++;
}
break;
default:
_impReturnError(IMP_ERR_BADBPP);
}
impMinValue(image) = vmin;
impMaxValue(image) = vmax;
/*
* Go to the appropriate position in the file and
* write the image data according to its raster encoding
* and bytes per pixel
*/
if (impIsVERBATIM(image)) {
if (_impSeekRow(image, row, channel) < 0)
_impReturnError(IMPerrno);
switch (impRasterBPP(image)) {
case 1:
if ((retv = _impWrite(image, image->tmpbuf, impXSize(image)))
!= impXSize(image))
_impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTWRITE);
return impXSize(image);
case 2:
count = impXSize(image) << 1;
if (image->dorev)
_impSwapShorts((ushort_t*)buffer, count);
retv = _impWrite(image, buffer, count);
if (image->dorev)
_impSwapShorts((ushort_t*)buffer, count);
if (retv != count)
_impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTWRITE);
return impXSize(image);
}
} else if (impIsRLE(image)) {
switch (impRasterBPP(image)) {
case 1:
count = rleCompactRow(buffer, 2, image->tmpbuf, 1,
impXSize(image));
if (rleSetRowSize(image, count, row, channel) < 0)
_impReturnError(IMPerrno);
if (_impSeekRow(image, row, channel) < 0)
_impReturnError(IMPerrno);
if ((retv = _impWrite(image, image->tmpbuf, count)) != count)
_impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTWRITE);
return impXSize(image);
case 2:
count = rleCompactRow(buffer, 2, image->tmpbuf, 2,
impXSize(image)) << 1;
if (rleSetRowSize(image, count, row, channel) < 0)
_impReturnError(IMPerrno);
if (_impSeekRow(image, row, channel) < 0)
_impReturnError(IMPerrno);
if (image->dorev)
_impSwapShorts((ushort_t*)image->tmpbuf, count);
retv = _impWrite(image, image->tmpbuf, count);
if (image->dorev)
_impSwapShorts((ushort_t*)image->tmpbuf, count);
if (retv != count)
_impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTWRITE);
return impXSize(image);
}
}
_impReturnError(IMP_ERR_BADIMAGE);
}
/**************************************************************************
*
* Function: impWriteRowB
*
* Description: Writes the specified image data as the specified row and
* channel. The data buffer for this function is of type unsigned
* char. This eliminates the need to do copying for 1 BPP images.
* Note that the image must be 1 BPP or an error is returned.
*
* Parameters:
* image (I) - image to write
* buffer (I) - data to write
* row (I) - image row to write
* channel (I) - image channel to write
*
* Return: Number of pixels written if no error. -1 and IMPerrno set if
* errors.
*
**************************************************************************/
int impWriteRowB(IMPImage *image, uchar_t *buffer, ushort_t row,
ushort_t channel)
{
register long vmin, vmax;
register ushort_t x;
register uchar_t *cptr;
int count, retv;
/*
* Sanity check the inputs
*/
assert(image != NULL);
assert(buffer != NULL);
/*
* Verify that the image is 1 BPP
*/
if (impRasterBPP(image) != IMP_RASTER_BPP1)
_impReturnError(IMP_ERR_BADBPP);
/*
* Verify we can write image
*/
if (!_impWriting(image))
_impReturnError(IMP_ERR_WRITEFLAG);
/*
* Use image dimension to sanitize the row and channel values
*/
if (impDimension(image) < 3)
channel = 0;
if (impDimension(image) < 2)
row = 0;
/*
* Determine the min and max image data values.
*/
vmin = impMinValue(image);
vmax = impMaxValue(image);
for (x = impXSize(image), cptr = buffer; x--; cptr++) {
/* LINTED */
if (*cptr > vmax) vmax = *cptr;
/* LINTED */
if (*cptr < vmin) vmin = *cptr;
}
impMinValue(image) = vmin;
impMaxValue(image) = vmax;
/*
* Go to the appropriate position in the file and
* write the image data according to its raster encoding
* and bytes per pixel
*/
if (impIsVERBATIM(image)) {
if (_impSeekRow(image, row, channel) < 0)
_impReturnError(IMPerrno);
if ((retv = _impWrite(image, buffer, impXSize(image)))
!= impXSize(image))
_impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTWRITE);
return impXSize(image);
} else if (impIsRLE(image)) {
/* LINTED */
count = rleCompactRow((short*)buffer, 1, image->tmpbuf, 1,
impXSize(image));
if (rleSetRowSize(image, count, row, channel) < 0)
_impReturnError(IMPerrno);
if (_impSeekRow(image, row, channel) < 0)
_impReturnError(IMPerrno);
if ((retv = _impWrite(image, image->tmpbuf, count)) != count)
_impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTWRITE);
return impXSize(image);
}
_impReturnError(IMP_ERR_BADIMAGE);
}
/**************************************************************************
*
* Function: impReadRow
*
* Description: Reads the specified image data as the specified row and
* channel.
*
* Parameters:
* image (I) - image to read
* buffer (I) - data to read
* row (I) - image row to read
* channel (I) - image channel to read
*
* Return: Number of pixels read if no error. -1 and IMPerrno set if
* errors.
*
**************************************************************************/
int impReadRow(IMPImage *image, short *buffer, ushort_t row, ushort_t channel)
{
register int count, retv;
/*
* Sanity check the inputs
*/
assert(image != NULL);
assert(buffer != NULL);
/*
* Verify we can read image
*/
if (!_impReading(image))
_impReturnError(IMP_ERR_READFLAG);
/*
* Use image dimension to sanitize the row and channel values
*/
if (impDimension(image) < 3)
channel = 0;
if (impDimension(image) < 2)
row = 0;
/*
* Seek to the specified row and channel and
* read the image data.
*/
if (_impSeekRow(image, row, channel) < 0)
_impReturnError(IMPerrno);
if (impIsVERBATIM(image)) {
switch (impRasterBPP(image)) {
case 1:
if ((retv = _impRead(image, image->tmpbuf, impXSize(image)))
!= impXSize(image)) {
_impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTREAD);
} else {
register uchar_t *cptr = (uchar_t*)image->tmpbuf;
register short *sptr = buffer;
register int i;
for (i = impXSize(image); i--;)
*sptr++ = *cptr++;
}
return impXSize(image);
case 2:
count = impXSize(image) << 1;
if ((retv = _impRead(image, buffer, count)) != count)
_impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTREAD);
if (image->dorev)
_impSwapShorts((ushort_t*)buffer, count);
return impXSize(image);
default:
_impReturnError(IMP_ERR_BADBPP);
}
}
else if (impIsRLE(image)) {
switch (impRasterBPP(image)) {
case 1:
if ((count = rleGetRowSize(image, row, channel)) < 0)
_impReturnError(IMPerrno);
if ((retv = _impRead(image, image->tmpbuf, count)) != count)
_impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTREAD);
rleExpandRow(image->tmpbuf, 1, buffer, 2);
return impXSize(image);
case 2:
if ((count = rleGetRowSize(image, row, channel)) < 0)
_impReturnError(IMPerrno);
if ((retv = _impRead(image, image->tmpbuf, count)) != count)
_impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTREAD);
if (image->dorev)
_impSwapShorts((ushort_t*)image->tmpbuf, count);
rleExpandRow(image->tmpbuf, 2, buffer, 2);
return impXSize(image);
default:
_impReturnError(IMP_ERR_BADBPP);
}
}
_impReturnError(IMP_ERR_BADIMAGE);
}
/**************************************************************************
*
* Function: impReadRowB
*
* Description: Reads the specified image data as the specified row and
* channel. The data buffer for this function is of type unsigned
* char. This eliminates the need to do copying for 1 BPP images.
* Note that the image must be 1 BPP or an error is returned.
*
* Parameters:
* image (I) - image to read
* buffer (I) - data to read
* row (I) - image row to read
* channel (I) - image channel to read
*
* Return: Number of pixels read if no error. -1 and IMPerrno set if
* errors.
*
**************************************************************************/
int impReadRowB(IMPImage *image, uchar_t *buffer, ushort_t row,
ushort_t channel)
{
register int count, retv;
/*
* Sanity check the inputs
*/
assert(image != NULL);
assert(buffer != NULL);
/*
* Verify that the image is 1 BPP
*/
if (impRasterBPP(image) != IMP_RASTER_BPP1)
_impReturnError(IMP_ERR_BADBPP);
/*
* Verify we can read image
*/
if (!_impReading(image))
_impReturnError(IMP_ERR_READFLAG);
/*
* Use image dimension to sanitize the row and channel values
*/
if (impDimension(image) < 3)
channel = 0;
if (impDimension(image) < 2)
row = 0;
/*
* Seek to the specified row and channel and
* read the image data.
*/
if (_impSeekRow(image, row, channel) < 0)
_impReturnError(IMPerrno);
if (impIsVERBATIM(image)) {
if ((retv = _impRead(image, buffer, impXSize(image)))
!= impXSize(image)) {
_impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTREAD);
}
return impXSize(image);
}
else if (impIsRLE(image)) {
if ((count = rleGetRowSize(image, row, channel)) < 0)
_impReturnError(IMPerrno);
if ((retv = _impRead(image, image->tmpbuf, count)) != count)
_impReturnError((retv < 0)? IMPerrno: IMP_ERR_SHORTREAD);
/* LINTED */
rleExpandRow(image->tmpbuf, 1, (short*)buffer, 1);
return impXSize(image);
}
_impReturnError(IMP_ERR_BADIMAGE);
}
/*
=========================================================================
LOCAL FUNCTIONS
=========================================================================
*/
/**************************************************************************
*
* Function: rleGetRowSize
*
* Description: Returns the number of bytes in the RLE compressed row
* for the row and channel specified.
*
* Parameters:
* image (I) - image file
* row (I) - row whose size is desired
* channel (I) - channel for the row
*
* Return: Row size in bytes if no error. -1 and IMPerrno set if error.
*
**************************************************************************/
static int rleGetRowSize(IMPImage *image, ushort_t row, ushort_t channel)
{
/*
* Validate the row and channel inputs
*/
if (_impBadRow(image, row, channel))
_impReturnError(IMP_ERR_BADROW);
switch (impDimension(image)) {
case 1:
return image->rowsize[0];
case 2:
return image->rowsize[row];
case 3:
return image->rowsize[row + channel * impYSize(image)];
default:
break;
}
_impReturnError(IMP_ERR_BADDIM);
}
/**************************************************************************
*
* Function: rleSetRowSize
*
* Description: Sets the number of bytes in the RLE compressed row
* for the row and channel specified in the appropriate header
* tables.
*
* Parameters:
* image (I) - image file
* count (I) - RLE row size in bytes
* row (I) - row whose size is to be set
* channel (I) - channel for the row
*
* Return: 0 if no error. -1 and IMPerrno set if error.
*
**************************************************************************/
static int rleSetRowSize(IMPImage *image, long count, ushort_t row,
ushort_t channel)
{
__int32_t *sizeptr;
/*
* Validate the row and channel inputs
*/
if (_impBadRow(image, row, channel))
_impReturnError(IMP_ERR_BADROW);
switch (impDimension(image)) {
case 1:
sizeptr = &image->rowsize[0];
image->rowstart[0] = image->rleend;
break;
case 2:
sizeptr = &image->rowsize[row];
image->rowstart[row] = image->rleend;
break;
case 3:
sizeptr = &image->rowsize[row + channel * impYSize(image)];
image->rowstart[row + channel * impYSize(image)] = image->rleend;
break;
default:
_impReturnError(IMP_ERR_BADDIM);
}
if (*sizeptr != -1)
image->wastebytes += *sizeptr;
*sizeptr = count;
image->rleend += count;
return 0;
}
/**************************************************************************
*
* Function: rleExpandRow
*
* Description: Performs an adaptive RLE expansion on the specified data.
* The function can convert between any combination of 1 and 2 byte
* per pixel formats on input and output.
*
* Parameters:
* rleBuf (I) - input RLE compressed buffer
* ibpp (I) - input bytes per pixel
* expBuf (O) - output expanded buffer
* obpp (I) - output bytes per pixel
*
* Return: none
*
**************************************************************************/
/* RLE expansion macro */
/* The algorithm here is an adaptive RLE encoding. If the run
starts with a negative count then we simply read absolute that
count pixels. If the value is positive we duplicate the pixel
count times. A zero count terminates the line.
*/
#define EXPAND_RLE while (1) { \
pixel = *iptr++; \
if (!(count = (pixel & 0x7f))) \
return; \
if (pixel & 0x80) { \
while (count--) \
*optr++ = *iptr++; \
} else { \
pixel = *iptr++; \
while (count--) \
*optr++ = pixel; \
} \
}
static void rleExpandRow(short *rleBuf, int ibpp, short *expBuf, int obpp)
{
register short pixel, count;
/*
* We declare the buffer pointers according to the
* specified ibpp and obpp
*/
if (ibpp == 1) {
register uchar_t *iptr = (uchar_t*)rleBuf;
if (obpp == 1) { /* ibpp == 1, obpp == 1 */
register uchar_t *optr = (uchar_t*)expBuf;
/* CONSTCOND */
/* LINTED */
EXPAND_RLE;
} else { /* ibpp == 1, obpp == 2 */
register short *optr = expBuf;
/* CONSTCOND */
EXPAND_RLE;
}
} else {
register short *iptr = rleBuf;
if (obpp == 1) { /* ibpp == 2, obpp == 1 */
register uchar_t *optr = (uchar_t*)expBuf;
/* CONSTCOND */
/* LINTED */
EXPAND_RLE;
} else { /* ibpp == 2, obpp == 2 */
register short *optr = expBuf;
/* CONSTCOND */
EXPAND_RLE;
}
}
}
/**************************************************************************
*
* Function: rleCompactRow
*
* Description: Performs an adaptive RLE compression on the specified data.
* The function can convert between any combination of 1 and 2 byte
* per pixel formats on input and output.
*
* Parameters:
* expBuf (O) - input uncompacted buffer
* ibpp (I) - input bytes per pixel
* rleBuf (I) - output RLE compressed buffer
* obpp (I) - output bytes per pixel
* npixels (I) - number of pixels in row
*
* Return: Size in bytes of the compacted row.
*
**************************************************************************/
/* RLE compression macro */
/* The algorithm here is an adaptive RLE encoding. If the run
starts with a negative count then we simply read absolute that
count pixels. If the value is positive we duplicate the pixel
count times. A zero count terminates the line.
*/
#define COMPACT_RLE while (iptr < ibufend) { \
sptr = iptr; \
iptr += 2; \
while ((iptr < ibufend) && \
((iptr[-2] != iptr[-1]) || \
(iptr[-1] != iptr[0]))) \
iptr++; \
iptr -= 2; \
count = iptr - sptr; \
while (count) { \
todo = (count > 126)? 126: count; \
count -= todo; \
*optr++ = 0x80 | todo; \
while (todo--) \
*optr++ = *sptr++; \
} \
sptr = iptr; \
cc = *iptr++; \
while ((iptr < ibufend) && (*iptr == cc)) \
iptr++; \
count = iptr - sptr; \
while (count) { \
todo = (count > 126)? 126: count; \
count -= todo; \
*optr++ = todo; \
*optr++ = cc; \
} \
} \
*optr++ = 0;
static int rleCompactRow(short *expBuf, int ibpp, short *rleBuf, int obpp,
int npixels)
{
register short todo, cc;
register long count;
/*
* We declare the buffer pointers according to the
* specified ibpp and obpp
*/
if (ibpp == 1 && obpp == 1) {
register uchar_t *iptr = (uchar_t*)expBuf;
register uchar_t *ibufend = iptr + npixels;
register uchar_t *sptr;
register uchar_t *optr = (uchar_t*)rleBuf;
/* LINTED */
COMPACT_RLE;
return optr - (uchar_t*)rleBuf;
}
if (ibpp == 1 && obpp == 2) {
register uchar_t *iptr = (uchar_t*)expBuf;
register uchar_t *ibufend = iptr + npixels;
register uchar_t *sptr;
register short *optr = rleBuf;
/* LINTED */
COMPACT_RLE;
return optr - rleBuf;
}
if (ibpp == 2 && obpp == 1) {
register short *iptr = expBuf;
register short *ibufend = iptr + npixels;
register short *sptr;
register uchar_t *optr = (uchar_t*)rleBuf;
/* LINTED */
COMPACT_RLE;
return optr - (uchar_t*)rleBuf;
}
{ /* ibpp == 2 && obpp == 2 */
register short *iptr = expBuf;
register short *ibufend = iptr + npixels;
register short *sptr;
register short *optr = rleBuf;
/* LINTED */
COMPACT_RLE;
return optr - rleBuf;
}
}